package com.bjsxt.messageConsumer.dao.impl;

import com.bjsxt.livegoods.pojo.Item;
import com.bjsxt.messageConsumer.dao.ItemDao4Redis;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Objects;

/**
 * @ClassName : ItemDao4ImplRedis
 * @Description :
 * @Author : ZWZ
 * @Date: 2021/8/27 15:26
 */
@Repository
public class ItemDao4ImplRedis implements ItemDao4Redis {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public Item get(String key) {
        return (Item) redisTemplate.opsForValue().get(key);
    }

    /**
     * 当前的方法，需要原子操作。要在更新之前，先查询一下 key 对应的商品，
     * 是否可以预定。如果可预定，则更新，如果不可预定，则忽略本次操作。
     * redisTemplate 的原子性操作，有一个非常容易出现问题的地方。
     * 在底层实现中，execute 回调方法，内部只做了 try..finally。没有捕获异常、 处理异常
     *
     * @param key
     * @param value
     * @return
     */
    @Override
    public boolean set(String key, Object value) {
        try {
            redisTemplate.setEnableTransactionSupport(true);
            // 执行多次操作，且操作是原子性操作的时候，可以通过回调逻辑，实现。
            List<Object> result = redisTemplate.execute(new SessionCallback<List<Object>>() {
                @Override
                public List<Object> execute(RedisOperations redisOperations) throws DataAccessException {
                    Item item = (Item) redisOperations.opsForValue().get(key);
                    if (item.getRented()) {
                        // 考虑到并发情况
                        return null;
                    }
                    // 开启事务， 通知 redis 后续的多条命令，是一个原子 操作。
                    redisOperations.multi();
                    // 未出租， 可以更新数据
                    redisOperations.opsForValue().set(key, value);
                    // 相当于是提交事务， 通知 redis，前置的命令都运行， 如果有任何命令出错，回滚，没有出错提交。
                    return redisOperations.exec();
                }
            });
            redisTemplate.setEnableTransactionSupport(false);
            if (Objects.isNull(result)) {
                return false;
            }
            return true;
        } catch (Exception e) {
            // 发生任何异常，redisTemplate 都会回滚事务，释放资源，但是不处理异
            e.printStackTrace();
            return false;
        }
    }

}
